Virtual function

In object-oriented programming, a virtual function or virtual method is a function or method whose behaviour can be overridden within an inheriting class by a function with the same signature. This concept is a very important part of the polymorphism portion of object-oriented programming (OOP).

Contents

Purpose

The concept of the virtual function solves the following problem:

In OOP when a derived class inherits a base class, an object of the derived class may be referred to (or cast) as either being the base class type or the derived class type. If there are base class methods overridden by the derived class, the method call behaviour is ambiguous.

The distinction between virtual and non-virtual resolves this ambiguity. If the function in question is designated virtual in the base class then the derived class' function would be called (if it exists). If it is not virtual, the base class' function would be called.

Virtual functions overcome the problems with the type-field solution by allowing the programmer to declare functions in a base class that can be redefined in each derived class.

In C++ virtual methods are declared by prepending the virtual keyword to the function's declaration.

Example

For example, a base class Animal could have a virtual function eat. Subclass Fish would implement eat() differently than subclass Wolf, but you can invoke eat() on any class instance referred to as Animal, and get the eat() behaviour of the specific subclass.

This allows a programmer to process a list of objects of class Animal, telling each in turn to eat (by calling eat()), with no knowledge of what kind of animal may be in the list. You also do not need to have knowledge of how each animal eats, or what the complete set of possible animal types might be.

C#

In C#, a base class must provide the virtual modifier for any virtual method, and derived classes must provide the override modifier for any overridden method inherited from a base class. The following is an example in C#.NET

using System;
using System.Collections.Generic;
 
namespace ConsoleApplication1
{
  public class Animal
  {
    public virtual void Eat()
    {
      Console.WriteLine("I eat like a generic Animal.");
    }
  }
 
  public class Wolf : Animal
  {
    public override void Eat()
    {
      Console.WriteLine("I eat like a wolf!");
    }
  }
 
  public class Fish : Animal
  {
    public override void Eat()
    {
      Console.WriteLine("I eat like a fish!");
    }
  }
 
  public class GoldFish : Fish
  {
    public override void Eat()
    {
      Console.WriteLine("I eat like a goldfish!");
    }
  }
 
  public class OtherAnimal : Animal
  {
    // Eat() method is not overridden, so the base class method will be used.
  }
 
  public class Program
  {
    public static void Main(string[] args)
    {
      IList<Animal> animals = new List<Animal>();
 
      animals.Add(new Animal());
      animals.Add(new Wolf());
      animals.Add(new Fish());
      animals.Add(new GoldFish());
      animals.Add(new OtherAnimal());
 
      foreach (Animal currentAnimal in animals)
      {
        currentAnimal.Eat();
      }
    }
  }
}

Output:

I eat like a generic Animal.
I eat like a wolf!
I eat like a fish!
I eat like a goldfish!
I eat like a generic Animal.

C++

The following is an example in C++.

#include <iostream>
#include <memory>
#include <vector>
 
class Animal {
public:
    virtual void eat() {
        std::cout << "I eat like a generic animal.\n";
    }
    // polymorphic deletes require a virtual base destructor
    virtual ~Animal() {
    }
};
 
class Wolf : public Animal {
public:
    void eat() {
        std::cout << "I eat like a wolf!\n";
    }
};
 
class Fish : public Animal {
public:
    void eat() {
        std::cout << "I eat like a fish!\n";
    }
};
 
class GoldFish : public Fish {
public:
    void eat() {
        std::cout << "I eat like a goldfish!\n";
    }
};
 
class OtherAnimal : public Animal {
};
 
int main() {
    std::vector<std::unique_ptr<Animal>> animals;
 
    animals.push_back(std::unique_ptr<Animal>(new Animal));
    animals.push_back(std::unique_ptr<Animal>(new Wolf));
    animals.push_back(std::unique_ptr<Animal>(new Fish));
    animals.push_back(std::unique_ptr<Animal>(new GoldFish));
    animals.push_back(std::unique_ptr<Animal>(new OtherAnimal));
 
    for (auto it = animals.begin(); it != animals.end(); ++it) {
        (*it)->eat();
    }
}

Output with the virtual function Animal::eat():

I eat like a generic animal.
I eat like a wolf!
I eat like a fish!
I eat like a goldfish!
I eat like a generic animal.

Output if Animal::eat() were not declared as virtual:

I eat like a generic animal.
I eat like a generic animal.
I eat like a generic animal.
I eat like a generic animal.
I eat like a generic animal.

D

The D programming language implements virtual functions. The override keyword tells the compiler that we don't want to define a new function, but rather override an existing one. Thus, if no function with the same name exists in the base class, the compiler breaks with an error. Note that the example below would produce the same output without the override keyword, but would also throw a compilation warning: Error: overrides base class function test.main.Animal.eat, but is not marked with 'override'.

import std.stdio;
 
void main()
{
    class Animal
    {
        void eat() { writefln("I eat like a generic Animal."); }
    }
 
    class Wolf : Animal
    {
        override void eat() { writefln("I eat like a Wolf."); }
    }
 
    class Fish : Animal
    {
        override void eat() { writefln("I eat like a Fish."); }
    }
 
    class GoldFish : Fish
    {
        override void eat() { writefln("I eat like a GoldFish."); }
    }
 
    class OtherAnimal : Animal
    {
    }
 
    Animal[] animals = new Animal[5];
    animals[0] = new Animal;
    animals[1] = new Wolf;
    animals[2] = new Fish;
    animals[3] = new GoldFish;
    animals[4] = new OtherAnimal;
 
    foreach ( Animal a; animals)
        a.eat();
}

Output:

I eat like a generic Animal.
I eat like a wolf!
I eat like a fish!
I eat like a goldfish!
I eat like a generic Animal.

Delphi.net

In Delphi, virtual methods are marked with virtual keyword. Methods in descendant classes that override a virtual method in ancestor class are marked with override keyword. If a virtual method is defined in an ancestor class, but not defined in a descendant class, descendant class will use ancestor class' implementation of that method.

Delphi also provides another similar method type called; "Dynamic method". Dynamic methods are marked with dynamic keyword instead of virtual keyword. Dynamic methods in Delphi have the same functionality of Virtual methods, but Delphi compiler implements them differently. In general, Virtual methods have better performance than Dynamic methods.[1] Here is an example of Virtual methods in Delphi:

{ Module 1: AnimalTypes.pas }
 
unit AnimalTypes;
 
interface
 
type
  Animal = class
  public
    procedure Eat; virtual;
  end;
 
  Wolf = class(Animal)
  public
    procedure Eat; override;
  end;
 
  Fish = class(Animal)
  public
    procedure Eat; override;
  end;
 
  GoldFish = class(Fish)
  public
    procedure Eat; override;
  end;
 
  OtherAnimal = class(Animal)
  public
    { Eat method is not overridden, so the base class method will be used. }
  end;
 
implementation
 
{ Animal }
procedure Animal.Eat;
begin
  WriteLn('I eat like a generic Animal.');
end;
 
{ Wolf }
procedure Wolf.Eat;
begin
  WriteLn('I eat like a wolf!');
end;
 
{ Fish }
procedure Fish.Eat;
begin
  WriteLn('I eat like a fish!');
end;
 
{ GoldFish }
procedure GoldFish.Eat;
begin
  WriteLn('I eat like a goldfish!');
end;
 
end.
{ Module 2: ConsoleApplication1.dpr }
 
program ConsoleApplication1;
 
{$APPTYPE CONSOLE}
 
uses
  Generics.Collections,
  AnimalTypes;
 
var
  Animals : TList<Animal>;
  CurrentAnimal : Animal;
begin
  Animals := TList<Animal>.Create;
  try
    Animals.Add(Animal.Create);
    Animals.Add(Wolf.Create);
    Animals.Add(Fish.Create);
    Animals.Add(GoldFish.Create);
    Animals.Add(OtherAnimal.Create);
 
    for CurrentAnimal in Animals do
      CurrentAnimal.Eat;
  finally
    Animals.Free;
  end;
end.

Output:

I eat like a generic Animal.
I eat like a wolf!
I eat like a fish!
I eat like a goldfish!
I eat like a generic Animal.

Groovy

Groovy has exactly the same OOP characteristics as Java and the Java code shown below will behave exactly the same way. However, one would probably write the example in a more concise way in Groovy, in order to make the code easier to read:

class Animal {
 
   void eat() { println "I eat like a generic Animal." }
}
 
class Wolf extends Animal {
 
   void eat() { println "I eat like a wolf!" }
}
 
class Fish extends Animal {
 
   void eat() { println "I eat like a fish!" }
}
 
class Goldfish extends Fish {
 
   void eat() { println "I eat like a goldfish!" }
}
 
class OtherAnimal extends Animal {}
 
for (animal in [ new Animal(), new Wolf(), new Fish(), new Goldfish(), new OtherAnimal() ]) {
 
    animal.eat()
}

Java

In Java, all non-static methods are by default "virtual functions". Only methods marked with the keyword final, which cannot be overridden, along with private methods, which are not inherited, are non-virtual. The following is an example of virtual methods in Java:

import java.util.*;
 
public class Animal 
{
   public void eat() 
   { 
      System.out.println("I eat like a generic Animal."); 
   }
 
   public static void main(String[] args) 
   {
      List<Animal> animals = new LinkedList<Animal>();
 
      animals.add(new Animal());
      animals.add(new Wolf());
      animals.add(new Fish());
      animals.add(new Goldfish());
      animals.add(new OtherAnimal());
 
      for (Animal currentAnimal : animals) 
      {
         currentAnimal.eat();
      }
   }
}
 
public class Wolf extends Animal 
{
   @Override
   public void eat() 
   { 
      System.out.println("I eat like a wolf!"); 
   }
}
 
public class Fish extends Animal 
{
   @Override
   public void eat() 
   { 
      System.out.println("I eat like a fish!"); 
   }
}
 
public class Goldfish extends Fish 
{
   @Override
   public void eat() 
   { 
      System.out.println("I eat like a goldfish!"); 
   }
}
 
public class OtherAnimal extends Animal {}

Output:

I eat like a generic Animal.
I eat like a wolf!
I eat like a fish!
I eat like a goldfish!
I eat like a generic Animal.

Python

In Python all class functions (methods) are virtual.

class Animal:
    def eat(self):
        print "I eat like a generic Animal."
 
class Wolf(Animal):
    def eat(self):
        print "I eat like a wolf!"
 
class Fish(Animal):
    def eat(self):
        print "I eat like a fish!"
 
class GoldFish(Fish):
    def eat(self):
        print "I eat like a goldfish!"
 
class OtherAnimal(Animal):
    pass
 
animals = [ Animal(), Wolf(), Fish(), GoldFish(), OtherAnimal() ] 
for a in animals:
    a.eat()

Output:

I eat like a generic Animal.
I eat like a wolf!
I eat like a fish!
I eat like a goldfish!
I eat like a generic Animal.

Ruby

In Ruby all instance methods are virtual.

class Animal
  def eat
    puts "I eat like a generic Animal."
  end
end
 
class Wolf < Animal
  def eat
    puts "I eat like a wolf!"
  end
end
 
class Fish < Animal
  def eat
    puts "I eat like a fish!"
  end
end
 
class GoldFish < Fish
  def eat
    puts "I eat like a goldfish!"
  end
end
 
class OtherAnimal < Animal
end
 
animals = [ Animal.new, Wolf.new, Fish.new, GoldFish.new, OtherAnimal.new ] 
animals.each {|a| a.eat }

Output:

I eat like a generic Animal.
I eat like a wolf!
I eat like a fish!
I eat like a goldfish!
I eat like a generic Animal.

VB.NET

In VB.NET, a base class must provide the Overridable modifier for any virtual method, and derived classes may provide the optional Overrides modifier for any overridden method inherited from a base class (this prevents a warning from being issued). The following is an example in VB.NET:

Imports System
Imports System.Collections.Generic
 
Namespace ConsoleApplication1
 
    Public Class Animal
        Public Overridable Sub Eat()
            Console.WriteLine("I eat like a generic Animal.")
        End Sub
    End Class
 
    Public Class Wolf
        Inherits Animal
        Public Overrides Sub Eat()
            Console.WriteLine("I eat like a wolf!")
        End Sub
    End Class
 
    Public Class Fish
        Inherits Animal
        Public Overrides Sub Eat()
            Console.WriteLine("I eat like a fish!")
        End Sub
    End Class
 
    Public Class Goldfish
        Inherits Fish
        Public Overrides Sub Eat()
            Console.WriteLine("I eat like a goldfish!")
        End Sub
    End Class
 
    Public Class OtherAnimal
        Inherits Animal
        'Eat() method is not overridden, so the base class method will be used.
    End Class
 
    Public Class Program
        Shared Sub Main()
            Dim animals As New List(Of Animal)
            animals.Add(New Animal())
            animals.Add(New Wolf())
            animals.Add(New Fish())
            animals.Add(New Goldfish())
            animals.Add(New OtherAnimal())
 
            For Each currentAnimal As Animal In animals
                currentAnimal.Eat()
            Next
        End Sub
    End Class
 
End Namespace

Output:

I eat like a generic Animal.
I eat like a wolf!
I eat like a fish!
I eat like a goldfish!
I eat like a generic Animal.

Abstract classes and pure virtual functions

A pure virtual function or pure virtual method is a virtual function that is required to be implemented by a derived class, if that class is not abstract. Classes containing pure virtual methods are termed "abstract"; they cannot be instantiated directly. A subclass of an abstract class can only be instantiated directly if all inherited pure virtual methods have been implemented by that class or a parent class. Pure virtual methods typically have a declaration (signature) and no definition (implementation).

As an example, an abstract base class MathSymbol may provide a pure virtual function doOperation(), and derived classes Plus and Minus implement doOperation() to provide concrete implementations. Implementing doOperation() would not make sense in the MathSymbol class, as MathSymbol is an abstract concept whose behaviour is defined solely for each given kind (subclass) of MathSymbol. Similarly, a given subclass of MathSymbol would not be complete without an implementation of doOperation().

Although pure virtual methods typically have no implementation in the class that declares them, pure virtual methods in C++ are permitted to contain an implementation in their declaring class, providing fallback or default behaviour that a derived class can delegate to, if appropriate.

Pure virtual functions are also used where the method declarations are being used to define an interface for which derived classes will supply all implementations. An abstract class serving as an interface contains only pure virtual functions, and no data members or ordinary methods. Use of purely abstract classes as interfaces works in C++ as it supports multiple inheritance. Because many OO languages do not support multiple inheritance they often provide a separate interface mechanism. This is seen in Java for example.

C++

In C++, pure virtual functions are declared using a special syntax (=  0), as demonstrated below.

class Abstract {
public:
   virtual void pure_virtual() = 0;
};

The pure virtual function declaration provides only the prototype of the method. Although an implementation of the pure virtual function is typically not provided in an abstract class, it may be included, although the definition may not be included at the point of declaration.[2] Every non-abstract child class is still required to override the method, but the implementation provided by the abstract class may be called in this way:

 void Abstract::pure_virtual() {
   // Do something
 }
 
 class Child : public Abstract {
   virtual void pure_virtual(); // no longer abstract, this class may be
                                // instantiated.
 };
 
 void Child::pure_virtual() {
   Abstract::pure_virtual(); // the implementation in the abstract class 
                             // is executed
 }

C# and Java

In C# and Java, pure virtual methods are declared using the abstract keyword. Such a method cannot have a body. A class containing abstract methods (either directly, or inherited and not overridden) must itself be declared abstract. (But the converse is not true - an abstract class is not required to have any abstract methods.) An abstract class cannot be instantiated. Any concrete (instantiable) class with an abstract class as its ancestor must implement all unimplemented abstract methods in order to successfully compile.

abstract class B {
    abstract void a_pure_virtual_function();
}

C# and Java also use interfaces. All of the methods declared in an interface are implicitly abstract:

interface C {
    void a_pure_virtual_function();
}

VB.NET

In VB.NET, pure virtual function may be declared using MustOverride keyword, which would make the class not instantiatable. If another class inherits it, it must provide an overriding method (using Overrides keyword, see above) in order to be instantiatable. Note that End Sub/ End Function/ End Property statement is not needed for pure virtual functions in VB.NET.

Public MustInherit Class Animal
    Public MustOverride Sub Eat()
End Class

Just like C# and Java, an interface may be used instead:

Public Interface Animal
    Public Sub Eat()
End Interface

The virtual philosophy

In C# and Java, a virtual function or virtual method is included into the language syntax with a different philosophy. C# has normally functions that are non-virtual, whereas Java's methods are by default virtual, but can be made non-virtual with the final keyword. There are reasons for this selection in both cases, which may be of interest:[3]

  1. Performance: If developers are not aware of the "cost" of making a method virtual, they may forget to declare it as final, which results in poor performance.
  2. Versioning: According to the "academic school", everything should be virtual, as there may arise one day the need to override a method. The "pragmatic school" says that one has to be careful about what is virtual, as a lot of promises are made by the compiler (call-back hook), which makes it an involved issue.

Behaviour during construction and destruction

Languages differ in their behaviour while the constructor or destructor of an object is running. For some languages, notably C++, the virtual dispatching mechanism has different semantics during construction and destruction of an object. While it is recommended that virtual function calls in constructors should be avoided for C++,[4] in some other languages, for example C# and Java, the derived implementation can be called during construction and design patterns such as the Abstract Factory Pattern actively promote this usage in languages supporting the ability.

C++

#include <iostream>
#include <string>
 
using namespace std;
 
struct A
{
  virtual string name() const { return "A"; } 
  virtual ~A() { cout << "Destructing " << name() << endl; }   
};
 
struct B : A
{
  B() { cout << "Constructing " << name() << endl; }
  virtual string name() const { return "B"; }
};
 
struct C : B
{
  virtual string name() const { return "C"; }
};
 
int main()
{
  C c; // Output: "Constructing B"
 
} // Output: "Destructing A"

Java

public class Base {
  public int length() { 
    return 0; 
  }
 
  public Base() {
    System.out.println("Constructing " + length());
  }
 
  static class Derived extends Base {
    String name;
    public Derived(String name) {
      this.name = (name != null) ? name : ""; // Class invariant this.name is not null
    }
    public int length() { 
      return name.length(); // Assume name is not null 
    } 
  }
 
  public static void  main(String[] args) {
    new Derived("Ooops");    // NullPointerException, Derived.name has not been assigned to yet
  }
}

This is because the constructor of Base is executed before the constructor of Derived. As the constructor of Base calls length(), a null pointer exception is thrown.

Virtual destructors

Object-oriented languages typically manage memory allocation and deallocation automatically when objects are created and destroyed. However, some object-oriented languages allow a custom destructor method to be implemented, if desired. One such language is C++, and as illustrated in the following example, it is important for a C++ base class to have a virtual destructor to ensure that the destructor from the most derived class will always be called.

In the example below having no virtual destructor, deleting an instance of class B will correctly call destructors for both B and A, if the object is deleted as an instance of B. An instance of B deleted via a pointer to its base class A will produce undefined behaviour.[5] On many implementations, the destructor for B will not be called in this situation.

 #include <iostream>
 using namespace std;
 
 class A
 {
 public:
 
   A() { }
   ~A() { cout << "Destroy A" << endl; }
 };
 
 class B : public A
 {
 public:
 
   B() { }
   ~B() { cout << "Destroy B" << endl; }
 };
 
 int main()
 {
   A* b1 = new B;
   B* b2 = new B;
 
   delete b1; // According to the C++ standard,
              // the behaviour of this is undefined.
              // Usually, only ~A() is called though b1 is an instance
              // of class B because ~A() is not declared virtual. 
   delete b2; // Calls destructors ~B() and ~A()
 
   return 0;
 }

Possible output:

Destroy A
Destroy B
Destroy A

Correctly declaring the destructor for class A as virtual ~A() will ensure that the destructor for class B is called in both cases with the example above.

References

  1. ^ Delphi in a Nutshell: Chapter 2
  2. ^ Standard C++ 98 - 10.4/2
  3. ^ Bill Venners (2003-09-15). "Versioning, Virtual, and Override: Non-Virtual is the Default". http://www.artima.com/: aritma developer. http://www.artima.com/intv/nonvirtual.html. Retrieved 2011-08-10. "There are several reasons. One is performance. [...] A more important issue is versioning. There are two schools of thought about virtual methods. The academic school of thought says, "Everything should be virtual, because I might want to override it someday." The pragmatic school of thought, which comes from building real applications that run in the real world, says, "We've got to be real careful about what we make virtual." [...]" 
  4. ^ Meyers, Scott (June 6, 2005). "Never Call Virtual Functions during Construction or Destruction". http://www.artima.com/cppsource/nevercall.html. 
  5. ^ ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §5.3.5 Delete [expr.delete] para. 3

See also